package zhoug.zui.swipe;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.Scroller;

import zhoug.logging.Logger;
import zhoug.zui.R;

import androidx.annotation.Nullable;

/**
 * 仿QQ向左侧滑菜单Item
 *
 * @Author 35574
 * @Date 2020/8/25
 * @Description
 */
public class ZUISwipeMenuLayout extends LinearLayout {
    private static final String TAG = ">>>ZUISwipeMenuLayout";
    private static boolean debug = false;
    private static final int STATE_CLOSED = 0;//关闭状态
    private static final int STATE_OPEN = 1;//状态
    private int mState = STATE_CLOSED;
    private int totalMenuWidth;//菜单View的总宽度
    private int minSwipeWidth;//触发自动滑动时移动的最短距离,默认为totalMenuWidth*1/4;

    private int touchSlop;//触发滑动的最小距离
    private Scroller mScroller;
    private static final int DURING = 100;
    private float downX;//按下时的x
    private float lastX;//上次的x
    private float downY;//按下时的y
    private boolean moved = false;//是否是自己拦截的移动
    private boolean openSwipe = true;//是否开启滑动

    public static void setDebug(boolean debug) {
        ZUISwipeMenuLayout.debug = debug;
    }

    public ZUISwipeMenuLayout(Context context) {
        this(context, null);
    }

    public ZUISwipeMenuLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ZUISwipeMenuLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOrientation(HORIZONTAL);
        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mScroller = new Scroller(context, new LinearInterpolator());
    }

    public void setOpenSwipe(boolean openSwipe) {
        this.openSwipe = openSwipe;
        //关闭侧滑
        if (!openSwipe && isMenuOpen()) {
            smoothCloseMenu();
        }
    }


    /**
     * 是否是打开状态
     *
     * @return
     */
    public boolean isMenuOpen() {
        boolean b = mState == STATE_OPEN;
        if (debug) {
            Logger.d(TAG, "isMenuOpen:" + b);
        }
        return b;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = getChildCount();
        if (count > 0) {
//            int menuWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
            int menuMaxHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
            if (menuMaxHeight < 0) {
                menuMaxHeight = 0;
            }
//            int menuHeightMeasureSpec = MeasureSpec.makeMeasureSpec(menuMaxHeight, MeasureSpec.EXACTLY);
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                ViewGroup.LayoutParams menuParams = child.getLayoutParams();
                if (menuParams instanceof LayoutParams && ((LayoutParams) menuParams).isMenu) {
//                    child.getVisibility() != View.GONE
                    int width = child.getMeasuredWidth();
                    if (debug) {
                        Logger.d(TAG, "自动测量:" + width);
                    }
                    int menuWidthMeasureSpec;
                    if (menuParams.width == ViewGroup.LayoutParams.WRAP_CONTENT ||
                            menuParams.width == ViewGroup.LayoutParams.MATCH_PARENT) {
                        menuWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                    } else {
                        menuWidthMeasureSpec = MeasureSpec.makeMeasureSpec(menuParams.width, MeasureSpec.EXACTLY);
                    }
                    int menuHeightMeasureSpec;
                    if (menuParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                        menuHeightMeasureSpec = MeasureSpec.makeMeasureSpec(menuMaxHeight, MeasureSpec.AT_MOST);
                    } else if (menuParams.height == ViewGroup.LayoutParams.MATCH_PARENT) {
                        menuHeightMeasureSpec = MeasureSpec.makeMeasureSpec(menuMaxHeight, MeasureSpec.EXACTLY);
                    } else {
                        menuHeightMeasureSpec = MeasureSpec.makeMeasureSpec(menuParams.height, MeasureSpec.EXACTLY);
                    }
                    child.measure(menuWidthMeasureSpec, menuHeightMeasureSpec);

                    /*if (menuParams.width < 0 || menuParams.height == ViewGroup.LayoutParams.MATCH_PARENT) {
                        child.measure(menuWidthMeasureSpec, menuHeightMeasureSpec);
                        menuParams.width = child.getMeasuredWidth();
                        menuParams.height = child.getMeasuredHeight();
                        child.setLayoutParams(menuParams);
                    }*/
                    if (debug) {
                        Logger.d(TAG, "菜单宽度:" + child.getMeasuredWidth());
                    }
                    if (debug) {
                        Logger.d(TAG, "##############");
                    }
                }
            }
        }
        if (debug) {
            Logger.d(TAG, "##############测量完成##############");
        }
        computeMenuTotalWidth();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        computeMenuTotalWidth();

    }

    private void computeMenuTotalWidth() {
        //计算出全部菜单按钮的总宽度
        int count = getChildCount();
        int totalMenuWidthNew = 0;
        if (count > 0) {
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                ViewGroup.LayoutParams params = child.getLayoutParams();
                if (child.getVisibility() != View.GONE && params instanceof LayoutParams && ((LayoutParams) params).isMenu) {
                    int menuWidth = child.getMeasuredWidth();
                    if (debug) {
                        Logger.d(TAG, "computeMenuTotalWidth : menuWidth=" + menuWidth);
                    }
                    totalMenuWidthNew += menuWidth;
                }
            }
        }
        if (debug) {
            Logger.d(TAG, "computeMenuTotalWidth totalMenuWidthNew=" + totalMenuWidthNew);
        }
        if (totalMenuWidth != totalMenuWidthNew) {
            totalMenuWidth = totalMenuWidthNew;
            //默认惯性滑动距离
            minSwipeWidth = totalMenuWidth / 4;
            int scrollX = getScrollX();
            if (scrollX > 0) {
                scrollTo(0, 0);
            }
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (!openSwipe) {
            return super.onInterceptTouchEvent(event);
        }
        if (debug) {
            Logger.d(TAG, "onInterceptTouchEvent:");
        }
        if (isMenuOpen()) {
            getParent().requestDisallowInterceptTouchEvent(true);
        }
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (debug) {
                    Logger.d(TAG, "onInterceptTouchEvent:ACTION_DOWN");
                }
                downX = event.getX();
                lastX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (debug) {
                    Logger.d(TAG, "onInterceptTouchEvent:ACTION_MOVE");
                }
                if (isInterceptMoveX(event)) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                moved = false;
                break;

        }
        return super.onInterceptTouchEvent(event);
    }

    /**
     * x移动的距离大于y,且大于最小距离时拦截事件
     *
     * @param event
     * @return
     */
    private boolean isInterceptMoveX(MotionEvent event) {
        if (!moved) {
            float x = event.getX();
            float y = event.getY();
            float disX = x - downX;
            float disY = y - downY;
            //如果y轴的偏移量大于x轴的偏移量,不在滑动
            if (Math.abs(disY) > Math.abs(disX)) {
                return false;
            }
            if (Math.abs(disX) >= touchSlop) {
                ViewParent parent = getParent();
                if (parent != null) {
                    parent.requestDisallowInterceptTouchEvent(true);
                }
                lastX = event.getX();
                moved = true;
                return true;
            }
        }
        return moved;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!openSwipe) {
            return super.onTouchEvent(event);
        }
        if (debug) {
            Logger.d(TAG, "onTouchEvent:");
        }
        int scrollX = 0;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (debug) {
                    Logger.d(TAG, "onTouchEvent:ACTION_DOWN");
                }
                downX = event.getX();
                lastX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float x = event.getX();
                if (isInterceptMoveX(event)) {
                    int deltaX = (int) (lastX - x);//这次需要移动的距离
                    scrollX = getScrollX() + deltaX;//移动后的距离
                    if (debug) {
                        Logger.d(TAG, "onTouchEvent:ACTION_MOVE :scrollX=" + scrollX);
                    }
                    //边界检查
                    if (scrollX < 0) {
                        scrollTo(0, 0);
                    } else if (scrollX > totalMenuWidth) {
                        scrollTo(totalMenuWidth, 0);
                    } else {
                        scrollBy(deltaX, 0);
                    }
                    lastX = x;
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (moved) {
                    scrollX = getScrollX();
                    if (debug) {
                        Logger.d(TAG, "onTouchEvent:ACTION_UP:scrollX=" + scrollX);
                    }
                    float dx = lastX - downX;
                    //左移,打开
                    if (dx < 0) {
                        if (scrollX > minSwipeWidth) {
                            mScroller.startScroll(scrollX, 0, totalMenuWidth - scrollX, 0, DURING);
                        } else {
                            mScroller.startScroll(scrollX, 0, -scrollX, 0, DURING);
                        }
                    } else {
                        //右移,关闭
                        if (scrollX < (totalMenuWidth - minSwipeWidth)) {
                            mScroller.startScroll(scrollX, 0, -scrollX, 0, DURING);
                        } else {
                            mScroller.startScroll(scrollX, 0, totalMenuWidth - scrollX, 0, DURING);
                        }
                    }
                    invalidate();
                    moved = false;
                    return true;
                }
        }
        super.onTouchEvent(event);
        return true;
    }

    /**
     * 打开状态不响应单击事件
     *
     * @return
     */
    @Override
    public boolean performClick() {
        if (isMenuOpen()) {
            return false;
        }
        return super.performClick();
    }

    /**
     * 打开状态不响应长按事件
     *
     * @return
     */
    @Override
    public boolean performLongClick() {
        if (isMenuOpen()) {
            return false;
        }
        return super.performLongClick();
    }

    /**
     * 关闭
     */
    public void smoothCloseMenu() {
        int scrollX = getScrollX();
        mScroller.startScroll(scrollX, 0, -scrollX, 0, DURING);
        postInvalidate();
    }

    /**
     * 关闭
     */
    public void closeMenu() {
        scrollTo(0, 0);
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            int currX = mScroller.getCurrX();
            scrollTo(currX, 0);
            invalidate();
        } else {
            int scrollX = getScrollX();
            if (debug) {
                Logger.d(TAG, "computeScroll:scrollX=" + scrollX);
            }
            if (scrollX == 0) {
                mState = STATE_CLOSED;
            } else {
                mState = STATE_OPEN;
            }
        }
    }


    //################自定义LayoutParams######################

    /**
     * 获取默认的LayoutParams
     *
     * @return
     */
    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        if (getOrientation() == HORIZONTAL) {
            return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        } else if (getOrientation() == VERTICAL) {
            return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        }
        return null;
    }

    /**
     * 检查LayoutParams是否合法
     *
     * @param p
     * @return
     */
    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof LayoutParams;
    }

    /**
     * 根据传入的lp生成自己的LayoutParams
     *
     * @param lp
     * @return
     */
    @Override
    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
        super.generateLayoutParams(lp);
        if (lp instanceof LayoutParams) {
            return new LayoutParams((LayoutParams) lp);
        } else if (lp instanceof MarginLayoutParams) {
            return new LayoutParams((MarginLayoutParams) lp);
        }
        return new LayoutParams(lp);
    }

    /**
     * 根据xml中的属性attrs生成自己的LayoutParams
     *
     * @param attrs
     * @return
     */
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    public static class LayoutParams extends LinearLayout.LayoutParams {
        public boolean isMenu = false;

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ZUISwipeMenuLayout_Layout);
            isMenu = a.getBoolean(R.styleable.ZUISwipeMenuLayout_Layout_layout_isMenu, false);
            a.recycle();
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(int width, int height, float weight) {
            super(width, height, weight);
        }

        public LayoutParams(ViewGroup.LayoutParams p) {
            super(p);
        }

        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(LayoutParams source) {
            super(source);
        }
    }


}

